#ifndef SIGNWAY_DOUBLE_LINK_H
#define SIGNWAY_DOUBLE_LINK_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef __cplusplus
#define nullptr NULL
#define bool int 
#define true 1
#define false 0
#define new(type, ...) ({\
    type* __t = (type*) malloc(sizeof(type));\
    *__t = (type){__VA_ARGS__};\
    __t; })
#endif

typedef struct _dlink {
   struct _dlink* next;
   struct _dlink* prev;
} dlink;

#define dlink_foreach(cur, head) for (cur = head->next; cur != head; cur = cur->next)
#define dlink_rforeach(cur, head) for (cur = head->prev; cur != head; cur = cur->prev)
#define dlink_insert_front(cur, data) do { \
      data->next = cur; \
      data->prev = cur->prev; \
      cur->prev->next = data; \
      cur->prev = data; \
   } while(0)

typedef bool (*dlink_one_cb)(dlink* node, void* arg); 
typedef int (*dlink_tow_cb)(dlink* node1, dlink* node2, void* arg); 

dlink* dlink_init();
dlink* dlink_init_from_link(dlink *head, size_t size);
dlink* dlink_init_from_range(dlink *begin, dlink* end, size_t size);
int dlink_get_size(dlink *head);
bool dlink_empty(dlink *head);
dlink* dlink_begin(dlink *head);
dlink* dlink_end(dlink *head);
dlink* dlink_front(dlink *head);
dlink* dlink_back(dlink *head);
void dlink_reverse(dlink *head);
void dlink_clear(dlink *head, dlink_one_cb destroy, void* arg);
void dlink_destory(dlink *head, dlink_one_cb destroy, void* arg);
void dlink_ifdestory(dlink *head, dlink_one_cb destroy, void* arg);
void dlink_push_front(dlink* head, dlink *data);
void dlink_push_back(dlink* head, dlink *data);
void dlink_push_index(dlink* head, dlink *data, int index);
dlink* dlink_pop_front(dlink *head);
dlink* dlink_pop_back(dlink *head);
dlink* dlink_find_first(dlink *head, dlink_one_cb find, void* arg);
dlink* dlink_find_last(dlink *head, dlink_one_cb find, void* arg);
dlink* dlink_delete(dlink *head, dlink* node);
dlink* dlink_delete_first(dlink *head, dlink_one_cb del, void* arg);
dlink* dlink_delete_last(dlink *head, dlink_one_cb del, void* arg);
void dlink_splice_head(dlink *position, dlink *head);
void dlink_splice_node(dlink *position, dlink *node);
void dlink_splice_range(dlink *position, dlink *first, dlink* last);
void dlink_merge(dlink *head1, dlink *head2, dlink_tow_cb cmp, void * arg);
void dlink_swap(dlink *head1, dlink *head2);
void dlink_sort(dlink* head, dlink_tow_cb cmp, void * arg);
#endif /* SIGNWAY_DOUBLE_LINK_H */
